package com.redis.controller;

import com.redis.annotation.CacheField;
import com.redis.annotation.CacheLock;
import com.redis.delay.RedisDelayedQueue;
import com.redis.delay.test.TestOrder;
import com.redis.delay.test.TestTask;
import com.redis.lock.SpelKeyGenerator;
import com.redis.service.TestService;
import com.redis.topic.TestEvent;
import jdk.nashorn.internal.objects.annotations.Getter;
import org.redisson.api.RLock;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author lizhilong
 * @Date 2020/12/5 22:59
 */

@RestController
public class TestController {

    @Resource
    private RedisDelayedQueue redisDelayedQueue;

    @Resource
    private RedissonClient redssionClient;
    @Resource
    private TestService testService;

    @GetMapping("/test/add/{time}")
    public String addQueue(@PathVariable("time") Long time) {
        TestOrder testOrder = new TestOrder();
        testOrder.setOrderId("abs");
        testOrder.setOrderName("日用品");
        redisDelayedQueue.addQueue(testOrder, time, TimeUnit.SECONDS, TestTask.class.getName());
        return "OK";
    }

    @GetMapping("/test/add/event/{eventName}")
    public String addEvent(@PathVariable("eventName") String eventName) {
        TestEvent testEvent = new TestEvent();
        testEvent.setEventName(eventName);
        RTopic testTopic = redssionClient.getTopic("testTopic");
        long publish = testTopic.publish(testEvent);
        return String.valueOf(publish);
    }

    /**
     * lock.lock() 获取锁，如果当前线程不能获取锁，则当前线程会阻塞，直到获取锁为止
     */
    @GetMapping("/test/lock")
    public String testLock() {

        CountDownLatch countDownLatch = new CountDownLatch(2);
        RLock lock = redssionClient.getLock("testLock");
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                Thread.sleep(10000);
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "Thread-1").start();


        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                Thread.sleep(10000);
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "Thread-2").start();


        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "ok";
    }

    /**
     * lock.lock() 获取锁，如果当前线程不能获取锁，则立刻返回false 否则返回true
     */
    @GetMapping("/test/trylock")
    public String testTrylock() {

        CountDownLatch countDownLatch = new CountDownLatch(2);
        RLock lock = redssionClient.getLock("testLock");
        new Thread(() -> {
            boolean tryLock = lock.tryLock();
            try {
                if (tryLock) {
                    System.out.println(Thread.currentThread().getName() + "获取到锁");
                    Thread.sleep(10000);
                    countDownLatch.countDown();
                } else {
                    countDownLatch.countDown();
                    throw new RuntimeException("获取锁失败");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }, "Thread-1").start();


        new Thread(() -> {
            boolean tryLock = lock.tryLock();
            try {
                if (tryLock) {
                    System.out.println(Thread.currentThread().getName() + "获取到锁");
                    Thread.sleep(10000);
                    countDownLatch.countDown();
                } else {
                    countDownLatch.countDown();
                    throw new RuntimeException("获取锁失败");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }, "Thread-2").start();
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "ok";
    }

    @PostMapping("/test/cacheLock")
    @CacheLock(prefix = "test")
    public String testCacheLock(@RequestHeader(value = "token") String appToken, @RequestBody TestEvent testEvent) {
        System.out.println("run......");
        return "OK";
    }

    @GetMapping("/test/cacheLock/{name}")
    @CacheLock(prefix = "test")
    public String testCacheLock(@PathVariable("name") @CacheField String name) {
        System.out.println("run......");
        return "OK";
    }


    @PostMapping("/test/cacheLock/param")
    @CacheLock(prefix = "test")
    public String testCacheLockParam(@RequestParam("name") @CacheField String name) {
        System.out.println("run......");
        return "OK";
    }


    @PostMapping("/test/cacheLock/time")
    @CacheLock(prefix = "test", keyGenerator = SpelKeyGenerator.class, lockTime = 10, waitTime = 2, keys = {"TestEvent.eventName"})
    public String testCacheLock(@RequestBody @CacheField TestEvent testEvent) {
        System.out.println("run......");
        return "OK";
    }

    @GetMapping("/test/cacheLock2")
    public String testCacheLock2() {
        CountDownLatch countDownLatch =new CountDownLatch(9);
        for (int i = 1; i < 10; i++) {
            new Thread(() -> {
                try {
                    TestEvent testEvent = new TestEvent();
                    testEvent.setEventName("测试事件" + 1);
                    TestOrder testOrder = new TestOrder();
                    testOrder.setOrderId("ord" + 1);
                    testOrder.setOrderName("ord" + 1);
                    testService.test(testEvent, testOrder);
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    countDownLatch.countDown();
                }

            }).start();
        }
        try {
            countDownLatch.await();
        }catch (Exception e){
            e.printStackTrace();
        }
        return "OK";
    }

    @GetMapping("/test/tryLock")
    public void testTryLock(){
        CountDownLatch countDownLatch = new CountDownLatch(2);
        RLock lock = redssionClient.getLock("testTryLock");
        new Thread(() -> {
            try {
                boolean tryLock = lock.tryLock(5, TimeUnit.SECONDS);
                if (tryLock) {
                    Thread.sleep(10000);
                } else {
                    System.out.println(Thread.currentThread().getName() + "获取锁失败");
                }
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if(lock.isHeldByCurrentThread()){
                    lock.unlock();
                }
            }

        }, "thread-1").start();


        new Thread(() -> {
            try {
                boolean tryLock = lock.tryLock(5, TimeUnit.SECONDS);
                if (tryLock) {
                    Thread.sleep(10000);
                } else {
                    System.out.println(Thread.currentThread().getName() + "获取锁失败");
                }
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if(lock.isHeldByCurrentThread()){
                    lock.unlock();
                }
            }

        }, "thread-2").start();

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("=================结束================");
    }

}
